/*!
    \copyright  Copyright (c) 2025 Qualcomm Technologies International, Ltd.
                All Rights Reserved.
                Qualcomm Technologies International, Ltd. Confidential and Proprietary.
    \file
    \ingroup    accessory_device_service
    \brief      Accessory Device Service implementation
*/

#include <logging.h>
#include "accessory_device_service_private.h"

#ifdef INCLUDE_ACCESSORY_DEVICE_SERVICE

#include "connection_manager.h"
#include "pairing.h"
#include "qualcomm_connection_manager.h"
#include "device_properties.h"
#include "device_db_serialiser.h"
#include "key_sync.h"
#include "pddu_map.h"

/*! Accessory device service module data. */
accessory_device_service_data_t accessory_device_service_data;

/*! \brief HCI disconnect reason code to use when an accessory needs to be disconnected in barge in scenarios */
#ifndef ACCESSORY_DEVICE_SERVICE_BARGE_IN_DISCONNECT_HCI_REASON_CODE
#define ACCESSORY_DEVICE_SERVICE_BARGE_IN_DISCONNECT_HCI_REASON_CODE      (HCI_ERROR_OETC_LOW_RESOURCE)
#endif

/*! \brief The default accessory priority to use upon accessory connection. Application can override this anytime by calling  
           AccessoryDeviceService_SetPriorityForAccessory() API. */
#ifndef ACCESSORY_DEVICE_SERVICE_DEFAULT_PRIORITY
#define ACCESSORY_DEVICE_SERVICE_DEFAULT_PRIORITY      (0)
#endif

static void accessoryDeviceService_ClearAccessoryDevice(accessory_device_t *device_entry)
{
    if (device_entry != NULL)
    {
        device_entry->state = ACCESSORY_DEVICE_SERVICE_STATE_IDLE;
        device_entry->type = ACCESSORY_DEVICE_SERVICE_DEVICE_TYPE_UNKNOWN;
        BdaddrTpSetEmpty(&device_entry->tp_addr);
    }
}

static void accessoryDeviceService_ClearAllAccessoryDevices(void)
{
    accessory_device_t *device_entry = NULL;

    ARRAY_FOREACH(device_entry, accessoryDeviceService_GetData()->accessory_devices)
    {
        accessoryDeviceService_ClearAccessoryDevice(device_entry);
    }
}

static accessory_device_t* accessoryDeviceService_CreateOrFindDeviceEntry(const tp_bdaddr *tp_addr)
{
    accessory_device_t *device_entry = AccessoryDeviceService_GetDeviceEntryForTpAddr(tp_addr);

    if (device_entry == NULL)
    {
        /* Create new entry */
        device_entry = AccessoryDeviceService_CreateDeviceEntry(tp_addr, ACCESSORY_DEVICE_SERVICE_DEVICE_TYPE_UNKNOWN, ACCESSORY_DEVICE_SERVICE_STATE_IDLE);
    }

    DEBUG_LOG_INFO("accessoryDeviceService_CreateOrFindDeviceEntry lap 0x%x device_entry 0x%x", tp_addr->taddr.addr.lap, device_entry);

    return device_entry;
}

/*! \brief Check if the maximum number of accessory connections has been reached or not */
static bool accessoryDeviceService_IsMaxConnectionLimitReached(void)
{
    accessory_device_t *device_entry = NULL;
    unsigned active_sm_count = 0;

    ARRAY_FOREACH(device_entry, accessoryDeviceService_GetData()->accessory_devices)
    {
        if (device_entry->state == ACCESSORY_DEVICE_SERVICE_STATE_CONNECTED)
        {
            active_sm_count++;
        }
    }

    DEBUG_LOG("accessoryDeviceService_IsMaxConnectionLimitReached conn_count %u status %d", 
              active_sm_count, active_sm_count >= ACCESSORY_DEVICE_SERVICE_MAX_CONNECTIONS);

    return active_sm_count >= ACCESSORY_DEVICE_SERVICE_MAX_CONNECTIONS;
}

static void accessoryDeviceService_DeleteDeviceIfUnpaired(tp_bdaddr *tp_addr)
{
    uint16 flags = DEVICE_FLAGS_NO_FLAGS;
    device_t device = BtDevice_GetDeviceForBdAddr(&tp_addr->taddr.addr);

    if (device != NULL)
    {
        appDeviceGetFlagsForDevice(device, &flags);

        if (flags & DEVICE_FLAGS_NOT_PAIRED)
        {
            appDeviceDeleteWithTpAddr(tp_addr);
        }
    }
}

static void accessoryDeviceService_StoreDeviceType(device_t device, accessory_device_service_device_type_t type)
{
    bool written = FALSE;

    if (Device_SetProperty(device, device_property_accessory_type, &type, sizeof(accessory_device_service_device_type_t)))
    {
        DeviceDbSerialiser_SerialiseDevice(device);
        written = TRUE;
    }

    DEBUG_LOG("accessoryDeviceService_StoreDeviceType  %d", written);
}

static accessory_device_service_device_type_t accessoryDeviceService_RetrieveDeviceType(device_t device)
{
    void *type;
    size_t size;
    accessory_device_service_device_type_t accessory_type = ACCESSORY_DEVICE_SERVICE_DEVICE_TYPE_UNKNOWN;

    if (Device_GetProperty(device, device_property_accessory_type, &type, &size))
    {
        accessory_type = *(accessory_device_service_device_type_t *)type;
    }

    DEBUG_LOG("accessoryDeviceService_RetrieveDeviceType  accessory_type %d size %d", accessory_type, size);

    return accessory_type;
}

static void accessoryDeviceService_SetDefaultAccessoryPriority(const tp_bdaddr *tp_addr)
{
    /* Set the default accessory priority */
    AccessoryDeviceService_SetPriorityForAccessory(tp_addr, !ACCESSORY_DEVICE_SERVICE_DEFAULT_PRIORITY);
}

static void accessoryDeviceService_SendConnectedIndNotification(const tp_bdaddr *tp_addr)
{
    MESSAGE_MAKE(ind, ACCESSORY_DEVICE_SERVICE_CONNECTED_IND_T);

    ind->tp_addr = *tp_addr;

    TaskList_MessageSend(TaskList_GetFlexibleBaseTaskList(accessoryDeviceService_GetClientList()), ACCESSORY_DEVICE_SERVICE_CONNECTED_IND, ind);
}

static void accessoryDeviceService_SendDisconnectedIndNotification(const tp_bdaddr *tp_addr, hci_status reason)
{
    MESSAGE_MAKE(ind, ACCESSORY_DEVICE_SERVICE_DISCONNECTED_IND_T);

    ind->tp_addr = *tp_addr;
    ind->status = (reason == hci_error_conn_timeout || reason == hci_error_lmp_response_timeout) ? ACCESSORY_DEVICE_SERVICE_STATUS_LINK_LOSS : ACCESSORY_DEVICE_SERVICE_STATUS_DISCONNECTED;

    TaskList_MessageSend(TaskList_GetFlexibleBaseTaskList(accessoryDeviceService_GetClientList()), ACCESSORY_DEVICE_SERVICE_DISCONNECTED_IND, ind);
}

/* \brief Handle a CON_MANAGER_TP_CONNECT_IND for LE connections */
static void accessoryDeviceService_HandleConManagerTpConnectInd(const CON_MANAGER_TP_CONNECT_IND_T *ind)
{
    const typed_bdaddr* taddr = &ind->tpaddr.taddr;

    DEBUG_LOG("accessoryDeviceService_HandleConManagerTpConnectInd type[%d] addr [%04x,%02x,%06lx] incoming [%d]",
              taddr->type, taddr->addr.nap, taddr->addr.uap, taddr->addr.lap, ind->incoming);

    if (ind->incoming)
    {
        if (
#ifndef INCLUDE_DEVICE_TEST_SERVICE
            BtDevice_IsPeerSetupComplete()
            &&
#endif
            !BtDevice_LeDeviceIsPeer(&ind->tpaddr))
        {
            tp_bdaddr resolved_tpbdaddr = {0};
            accessory_device_t *device_entry = NULL;
            device_t device = NULL;

            if (ConManagerResolveTpaddr(&ind->tpaddr, &resolved_tpbdaddr))
            {
                DEBUG_LOG("accessoryDeviceService_HandleConManagerTpConnectInd resolved addr to [%04x,%02x,%06lx]",
                          resolved_tpbdaddr.taddr.addr.nap,
                          resolved_tpbdaddr.taddr.addr.uap,
                          resolved_tpbdaddr.taddr.addr.lap);
            }

            if (!AccessoryDeviceService_IsAccessoryDevice(&resolved_tpbdaddr))
            {
                /* Ignore as not from an accessory */
                return;
            }

            /* We do not support BREDR accessories for now, so if bychance it connects, place disconnect request immediately. */
            if (resolved_tpbdaddr.transport == TRANSPORT_BREDR_ACL)
            {
                ConManagerReleaseTpAclWithReasonCode(&ind->tpaddr, ACCESSORY_DEVICE_SERVICE_BARGE_IN_DISCONNECT_HCI_REASON_CODE);
                return;
            }

            /* Move the state to connected */
            device_entry = PanicNull(accessoryDeviceService_CreateOrFindDeviceEntry(&resolved_tpbdaddr));
            device_entry->state = ACCESSORY_DEVICE_SERVICE_STATE_CONNECTED;

            device = PanicNull(BtDevice_GetDeviceForBdAddr(&resolved_tpbdaddr.taddr.addr));
            device_entry->type = accessoryDeviceService_RetrieveDeviceType(device);

            /* Set default priority for this accessory device (if default priority is configured) */
            accessoryDeviceService_SetDefaultAccessoryPriority(&ind->tpaddr);

            accessoryDeviceService_SendConnectedIndNotification(&ind->tpaddr);

            DEBUG_LOG("accessoryDeviceService_HandleConManagerTpConnectInd received for lap 0x%x device_entry 0x%x", resolved_tpbdaddr.taddr.addr.lap, device_entry);
        }
    }
}

/* \brief Handle a CON_MANAGER_TP_DISCONNECT_IND for LE disconnections */
static void accessoryDeviceService_HandleConManagerTpDisconnectInd(const CON_MANAGER_TP_DISCONNECT_IND_T *ind)
{
    accessory_device_t *device_entry;

    if (ind->tpaddr.transport == TRANSPORT_BREDR_ACL)
    {
        /* At the moment, we do not support BREDR connection for accessories */
        return;
    }

    device_entry = AccessoryDeviceService_GetDeviceEntryForTpAddr(&ind->tpaddr);

    DEBUG_LOG("accessoryDeviceService_HandleConManagerTpDisconnectInd device_entry[%p] type[%d] addr [%04x,%02x,%06lx], enum:hci_status:%u",
                   device_entry,
                   ind->tpaddr.taddr.type,
                   ind->tpaddr.taddr.addr.nap,
                   ind->tpaddr.taddr.addr.uap,
                   ind->tpaddr.taddr.addr.lap,
                   ind->reason);

    if (device_entry != NULL)
    {
        accessoryDeviceService_DeleteDeviceIfUnpaired(&device_entry->tp_addr);

        /* Move the state to idle and clear the entry. On the next reconnection, check the BT device entry instead of the accessory list
           to determine if it is an accessory */
        accessoryDeviceService_ClearAccessoryDevice(device_entry);

        accessoryDeviceService_SendDisconnectedIndNotification(&ind->tpaddr, ind->reason);
    }
}

/*! \brief Callback to resolve the conflicts happened during device merge ie, BtDevice_Merge() */
static device_merge_action_t accessoryDeviceService_DeviceMergeResolveCallback(device_t source_device, device_t target_device,
                                                                         device_property_t property_id)
{
    device_merge_action_t resolve_action = DEVICE_MERGE_ACTION_UNRESOLVABLE;
    deviceType *source_object = NULL, *target_object = NULL;
    size_t source_size = 0, target_size = 0;

    PanicFalse(Device_GetProperty(source_device, property_id, (void *)&source_object, &source_size));
    PanicFalse(Device_GetProperty(target_device, property_id, (void *)&target_object, &target_size));
    PanicFalse(source_size == target_size);

    if (property_id == device_property_type)
    {
        PanicFalse(source_size == sizeof(deviceType));

        if (*((deviceType*)source_object) == DEVICE_TYPE_HANDSET_LE && *((deviceType*)target_object) == DEVICE_TYPE_ACCESSORY)
        {
            /* This is expected as if accessory device connects over random first, handset service may create DEVICE_TYPE_HANDSET_LE */
            resolve_action = DEVICE_MERGE_ACTION_ACCEPT_TARGET_LIST;
        }
    }
    else if (property_id == device_property_flags)
    {
        uint16 source_flag, target_flag, source_flag_conflict_bits;

        PanicFalse(source_size == sizeof(uint16));
        source_flag = *((uint16*)source_object);
        target_flag = *((uint16*)target_object);
        source_flag_conflict_bits = (source_flag ^ target_flag) & source_flag;

        /* Check if this conflict happened due to bit DEVICE_FLAGS_NOT_PAIRED in the source device */
        if (source_flag_conflict_bits == DEVICE_FLAGS_NOT_PAIRED)
        {
            /* This is expected to happen as the device created by handset device may not be having paired flag. */
            resolve_action = DEVICE_MERGE_ACTION_ACCEPT_TARGET_LIST;
        }
    }
    else if (property_id == device_property_gatt_service_discovery)
    {
        /* This property can be set to 1 upon service discovery completion for handset LE device. If conflict
           happen due to this we need to use the value in handset LE device as merged value */
        if (*((uint8*)source_object) == 1)
        {
            resolve_action = DEVICE_MERGE_ACTION_ACCEPT_SOURCE_LIST;
         }
    }

    DEBUG_LOG("accessoryDeviceService_DeviceMergeResolveCallback property %d resolve_action %d", property_id, resolve_action);

    return resolve_action;
}

/* \brief Handles the pairing related messages */
static void accessoryDeviceService_HandlePairingActivity(const PAIRING_ACTIVITY_T* pair_activity)
{
    DEBUG_LOG("accessoryDeviceService_HandlePairingActivity status enum:pairingActivityStatus:%u", pair_activity->status);

    switch (pair_activity->status)
    {
        case pairingActivityInProgress:
            break;

        case pairingActivityNotInProgress:
            break;

        case pairingActivitySuccess:
            {
                device_t device = BtDevice_GetDeviceForBdAddr(&pair_activity->device_addr);
                device_t dev_le = BtDevice_GetDeviceWithRraThatResolvesToPublicAddr(&pair_activity->device_addr);
                tp_bdaddr random_tp_addr, paired_address;
                accessory_device_t *device_entry = NULL;

                BdaddrTpSetEmpty(&random_tp_addr);

                if (BtDevice_IsDeviceAccessory(device))
                {
                    DEBUG_LOG_INFO("accessoryDeviceService_HandlePairingActivity pairingSuccess addr %04x %02x %06x perm %u",
                                   pair_activity->device_addr.nap, pair_activity->device_addr.uap, pair_activity->device_addr.lap,
                                   pair_activity->permanent);

                    /* If we have an LE device with matching random address, then it needs to be merged/updated to accessory device */
                    if(dev_le != NULL && pair_activity->permanent)
                    {
                        BtDevice_GetRandomTpAddrForDevice(dev_le, &random_tp_addr);
                        BtDevice_Merge(dev_le, device, accessoryDeviceService_DeviceMergeResolveCallback, TRUE);
                    }

                    DEBUG_LOG("accessoryDeviceService_HandlePairingActivity Synchronise Link Keys");
                    PanicFalse(BtDevice_SetFlags(device, DEVICE_FLAGS_NOT_PAIRED, 0));
                    PanicFalse(BtDevice_SetFlags(device, DEVICE_FLAGS_HANDSET_ADDRESS_FORWARD_REQD, DEVICE_FLAGS_HANDSET_ADDRESS_FORWARD_REQD));

                    /* Now that we have successfully paired, we can set the link behavior within bluestack to disable connection retires */
                    BtDevice_SetLinkBehavior(&pair_activity->device_addr);

#if defined(INCLUDE_MIRRORING) && !defined(DISABLE_KEY_SYNC)
                    /* Sync the newly paired device with the peer */
                    KeySync_Sync();
#endif
                    /* Update the PDL with the device in the persistent device data. This is in order to ensure
                    we don't lose device information in case of device disconnecting right after pairing 
                    without a profile connection */
                    if (BtDevice_isKnownBdAddr(&pair_activity->device_addr))
                    {
                        DEBUG_LOG("accessoryDeviceService_HandlePairingActivity Known Device, update DB for only that dev");
                        DeviceDbSerialiser_SerialiseDevice(device);
                    }

                    /* Move the state to connected */
                    paired_address.transport = TRANSPORT_BLE_ACL;
                    paired_address.taddr.type = TYPED_BDADDR_PUBLIC;
                    paired_address.taddr.addr = pair_activity->device_addr;

                    device_entry = PanicNull(accessoryDeviceService_CreateOrFindDeviceEntry(&paired_address));
                    device_entry->state = ACCESSORY_DEVICE_SERVICE_STATE_CONNECTED;
                    accessoryDeviceService_StoreDeviceType(device, device_entry->type);

                    if (!BdaddrTpIsEmpty(&random_tp_addr))
                    {
                        /* Accessory device connected over random address. So change the address associated with the entry to this
                            random so that when disconnection happens we will be able to get the entry correctly. */
                        device_entry->tp_addr = random_tp_addr;
                    }

                    /* Set default priority for this accessory device (if default priority is configured) */
                    accessoryDeviceService_SetDefaultAccessoryPriority(&device_entry->tp_addr);

                    accessoryDeviceService_SendConnectedIndNotification(&device_entry->tp_addr);
                }
            }
            break;

        default:
            break;
    }
}

/*! \brief Handle LE barge in indication */
static void accessoryDeviceService_HandleLeBargeInInd(QCOM_CON_MANAGER_LE_BARGE_IN_IND_T* msg)
{
    tp_bdaddr barge_in_addr;

    /* Fill in barge in information */
    barge_in_addr.transport = TRANSPORT_BLE_ACL;
    barge_in_addr.taddr = msg->barge_in_address;

    if (!AccessoryDeviceService_IsAccessoryDevice(&barge_in_addr))
    {
        /* Ignore as not from an accessory */
        return;
    }

    DEBUG_LOG_INFO("accessoryDeviceService_HandleLeBargeInInd lap 0x%x", msg->barge_in_address.addr.lap);

    if (!accessoryDeviceService_IsMaxConnectionLimitReached())
    {
        QcomConManagerAcceptLeBargeInConnection(&barge_in_addr);
    }
    else
    {
        /* Reject the connection. This will end up in disconnection in remote side */
        QcomConManagerRejectLeBargeInConnection(&barge_in_addr, ACCESSORY_DEVICE_SERVICE_BARGE_IN_DISCONNECT_HCI_REASON_CODE);
    }
}

/* \brief Main message handler of accessory device service */
static void accessoryDeviceService_MessageHandler(Task task, MessageId id, Message message)
{
    UNUSED(task);
    UNUSED(message);

    switch (id)
    {
        case CON_MANAGER_TP_CONNECT_IND:
            accessoryDeviceService_HandleConManagerTpConnectInd((const CON_MANAGER_TP_CONNECT_IND_T *) message);
            break;

        case CON_MANAGER_TP_DISCONNECT_IND:
            accessoryDeviceService_HandleConManagerTpDisconnectInd((const CON_MANAGER_TP_DISCONNECT_IND_T *) message);
            break;

        case PAIRING_ACTIVITY:
            accessoryDeviceService_HandlePairingActivity((PAIRING_ACTIVITY_T*) message);
            break;

        case QCOM_CON_MANAGER_LE_BARGE_IN_IND:
            accessoryDeviceService_HandleLeBargeInInd((QCOM_CON_MANAGER_LE_BARGE_IN_IND_T*) message);
            break;

        default:
            DEBUG_LOG_V_VERBOSE("accessoryDeviceService_MessageHandler Unhandled msg id 0x%x", id);
            break;
    }
}

static pdd_size_t accessoryDeviceService_GetDeviceDataLength(device_t device)
{
    void *config = NULL;
    size_t config_size = 0;

    if (!Device_GetProperty(device, device_property_accessory_type, &config, &config_size))
    {
        config_size = 0;
    }

    return config_size;
}

static void accessoryDeviceService_SerialiseDeviceData(device_t device, void *buf, pdd_size_t offset)
{
    void *config = NULL;
    size_t config_size = 0;
    UNUSED(offset);

    if (Device_GetProperty(device, device_property_accessory_type, &config, &config_size))
    {
        memcpy(buf, config, config_size);
    }
}

static void accessoryDeviceService_DeserialiseDeviceData(device_t device, void *buf, pdd_size_t data_length, pdd_size_t offset)
{
    UNUSED(offset);

    Device_SetProperty(device, device_property_accessory_type, buf, data_length);
}

void AccessoryDeviceService_RegisterAsPersistentDeviceDataUser(void)
{
    DeviceDbSerialiser_RegisterPersistentDeviceDataUser(
        PDDU_ID_ACCESSORY_DEVICE_SERVICE,
        accessoryDeviceService_GetDeviceDataLength,
        accessoryDeviceService_SerialiseDeviceData,
        accessoryDeviceService_DeserialiseDeviceData);
}

accessory_device_t* AccessoryDeviceService_CreateDeviceEntry(const tp_bdaddr *tp_addr,
                                                       accessory_device_service_device_type_t type,
                                                       accessory_device_service_state_t state)
{
    tp_bdaddr empty_address;
    accessory_device_t *device_entry;

    BdaddrTpSetEmpty(&empty_address);
    device_entry = AccessoryDeviceService_GetDeviceEntryForTpAddr(&empty_address);

    if (device_entry != NULL)
    {
        device_entry->tp_addr = *tp_addr;
        device_entry->type = type;
        device_entry->state = state;
    }

    return device_entry;
}

accessory_device_t* AccessoryDeviceService_GetDeviceEntryForTpAddr(const tp_bdaddr *tp_addr)
{
    accessory_device_t *device_entry = NULL;
    tp_bdaddr resolved_tp_addr, resolved_device_entry_tp_addr;

    (void) ConManagerResolveTpaddr(tp_addr, &resolved_tp_addr);

    ARRAY_FOREACH(device_entry, accessoryDeviceService_GetData()->accessory_devices)
    {
        if (BdaddrTpIsSame(&device_entry->tp_addr, &resolved_tp_addr) ||
            BdaddrTpIsSame(&device_entry->tp_addr, tp_addr))
        {
            return device_entry;
        }

        (void) ConManagerResolveTpaddr(&device_entry->tp_addr, &resolved_device_entry_tp_addr);

        if (BdaddrTpIsSame(&resolved_device_entry_tp_addr, &resolved_tp_addr) ||
            BdaddrTpIsSame(&resolved_device_entry_tp_addr, tp_addr))
        {
            return device_entry;
        }
    }

    return NULL;
}

void AccessoryDeviceService_Reset(void)
{
    accessoryDeviceService_ClearAllAccessoryDevices();
}

bool AccessoryDeviceService_Init(Task task)
{
    UNUSED(task);

    DEBUG_LOG_INFO("AccessoryDeviceService_Init");

    memset(&accessory_device_service_data, 0, sizeof(accessory_device_service_data));
    accessory_device_service_data.task_data.handler = accessoryDeviceService_MessageHandler;
    accessoryDeviceService_ClearAllAccessoryDevices();
    TaskList_InitialiseWithCapacity(accessoryDeviceService_GetClientList(), ACCESSORY_DEVICE_SERVICE_CLIENT_LIST_INIT_CAPACITY);

    ConManagerRegisterTpConnectionsObserver(cm_transport_all, accessoryDeviceService_GetTask());
    Pairing_ActivityClientRegister(accessoryDeviceService_GetTask());
    QcomConManagerRegisterBargeInClient(accessoryDeviceService_GetTask());

    return TRUE;
}

UNITCODESECTION(KEEP)
bool AccessoryDeviceService_AddDeviceInfo(tp_bdaddr *tp_addr, accessory_device_service_device_type_t type)
{
    bool status = FALSE;
    device_t device = BtDevice_GetDeviceForBdAddr(&tp_addr->taddr.addr);

    if (AccessoryDeviceService_GetDeviceEntryForTpAddr(tp_addr) != NULL || device != NULL)
    {
        /* Return as an entry already existing with the same address */
        DEBUG_LOG_WARN("AccessoryDeviceService_AddDeviceInfo lap 0x%x fails as entry already exists", tp_addr->taddr.addr.lap);
        return FALSE;
    }

    /* Add the new accessory into the list */
    if (AccessoryDeviceService_CreateDeviceEntry(tp_addr, type, ACCESSORY_DEVICE_SERVICE_STATE_PAIRING) != NULL)
    {
        status = TRUE;
        device = PanicNull(BtDevice_GetDeviceCreateIfNewWithTpAddr(tp_addr, DEVICE_TYPE_ACCESSORY));
        BtDevice_SetFlags(device, DEVICE_FLAGS_NOT_PAIRED, DEVICE_FLAGS_NOT_PAIRED);
    }

    DEBUG_LOG_INFO("AccessoryDeviceService_AddDeviceInfo lap 0x%x type enum:accessory_device_service_device_type_t:%d status %d", 
                   tp_addr->taddr.addr.lap, type, status);

    return status;
}

UNITCODESECTION(KEEP)
bool AccessoryDeviceService_RemoveDeviceInfo(tp_bdaddr *tp_addr)
{
    bool status = FALSE;
    accessory_device_t *device_entry = AccessoryDeviceService_GetDeviceEntryForTpAddr(tp_addr);

    /* For now, we do not support the removal in connected state */
    if (device_entry != NULL && device_entry->state != ACCESSORY_DEVICE_SERVICE_STATE_CONNECTED)
    {
        /* Clear the entry */
        status = TRUE;
        accessoryDeviceService_ClearAccessoryDevice(device_entry);

        /* Delete the device if it is an unpaired. */
        accessoryDeviceService_DeleteDeviceIfUnpaired(tp_addr);
    }

    DEBUG_LOG_INFO("AccessoryDeviceService_RemoveDeviceInfo lap 0x%x status %d", tp_addr->taddr.addr.lap, status);

    return status;
}

bool AccessoryDeviceService_IsAccessoryDevice(tp_bdaddr *tp_addr)
{
    bool is_accessory = FALSE;
    device_t device = BtDevice_GetDeviceForBdAddr(&tp_addr->taddr.addr);

    /* Check if associated device type is accessory or not. */
    if (BtDevice_IsDeviceAccessory(device))
    {
        is_accessory = TRUE;
    }

    DEBUG_LOG("AccessoryDeviceService_IsAccessoryDevice lap 0x%x is_accessory %d", tp_addr->taddr.addr.lap, is_accessory);

    return is_accessory;
}

accessory_device_service_device_type_t AccessoryDeviceService_GetDeviceType(tp_bdaddr *tp_addr)
{
    accessory_device_t *device_entry = AccessoryDeviceService_GetDeviceEntryForTpAddr(tp_addr);

    return device_entry != NULL ? device_entry->type : ACCESSORY_DEVICE_SERVICE_DEVICE_TYPE_UNKNOWN;
}

UNITCODESECTION(KEEP)
bool AccessoryDeviceService_DisconnectAccessory(tp_bdaddr *tp_addr, uint8 reason_code)
{
    accessory_device_t *device_entry = AccessoryDeviceService_GetDeviceEntryForTpAddr(tp_addr);
    bool status = FALSE;

    if (device_entry != NULL && device_entry->state == ACCESSORY_DEVICE_SERVICE_STATE_CONNECTED)
    {
        ConManagerReleaseTpAclWithReasonCode(tp_addr, reason_code);
        status = TRUE;
    }

    DEBUG_LOG_INFO("AccessoryDeviceService_DisconnectAccessory lap 0x%x status : %d, reason_code :%d", tp_addr->taddr.addr.lap, status, reason_code);

    return status;
}

UNITCODESECTION(KEEP)
bool AccessoryDeviceService_SetPriorityForAccessory(tp_bdaddr *tp_addr, bool is_low_priority)
{
    accessory_device_t *device_entry = AccessoryDeviceService_GetDeviceEntryForTpAddr(tp_addr);
    bool status = FALSE;

    if (device_entry != NULL)
    {
        QcomConManagerControlLinkTypePriorityReq(tp_addr, is_low_priority);
        status = TRUE;
    }

    DEBUG_LOG_INFO("AccessoryDeviceService_SetPriorityForAccessory lap 0x%x is_low_priority :%d", tp_addr->taddr.addr.lap, is_low_priority);

    return status;
}

void AccessoryDeviceService_ClientRegister(Task client_task)
{
    TaskList_AddTask(TaskList_GetFlexibleBaseTaskList(accessoryDeviceService_GetClientList()), client_task);
}

void AccessoryDeviceService_ClientUnregister(Task client_task)
{
    TaskList_RemoveTask(TaskList_GetFlexibleBaseTaskList(accessoryDeviceService_GetClientList()), client_task);
}

#else /* INCLUDE_ACCESSORY_DEVICE_SERVICE */

void AccessoryDeviceService_RegisterAsPersistentDeviceDataUser(void)
{
    return;
}

bool AccessoryDeviceService_Init(Task task)
{
    UNUSED(task);
    return FALSE;
}

bool AccessoryDeviceService_AddDeviceInfo(tp_bdaddr *tp_addr, accessory_device_service_device_type_t type)
{
    UNUSED(tp_addr);
    UNUSED(type);
    return FALSE;
}

bool AccessoryDeviceService_RemoveDeviceInfo(tp_bdaddr *tp_addr)
{
    UNUSED(tp_addr);
    return FALSE;
}

bool AccessoryDeviceService_IsAccessoryDevice(tp_bdaddr *tp_addr)
{
    UNUSED(tp_addr);
    return FALSE;
}

accessory_device_service_device_type_t AccessoryDeviceService_GetDeviceType(tp_bdaddr *tp_addr)
{
    UNUSED(tp_addr);
    return ACCESSORY_DEVICE_SERVICE_DEVICE_TYPE_UNKNOWN;
}

bool AccessoryDeviceService_DisconnectAccessory(tp_bdaddr *tp_addr, uint8 reason_code)
{
    UNUSED(tp_addr);
    UNUSED(reason_code);

    return FALSE;
}

bool AccessoryDeviceService_SetPriorityForAccessory(tp_bdaddr *tp_addr, bool is_low_priority)
{
    UNUSED(tp_addr);
    UNUSED(is_low_priority);

    return FALSE;
}

void AccessoryDeviceService_ClientRegister(Task client_task)
{
    UNUSED(client_task);
}

void AccessoryDeviceService_ClientUnregister(Task client_task)
{
    UNUSED(client_task);
}

#endif /* INCLUDE_ACCESSORY_DEVICE_SERVICE */
